﻿#region Opis pliku
//-----------------------------------------------------------------------------
// Emitter.cs
// Autor: Jan Czarnowski
// 30.10.2012
//-----------------------------------------------------------------------------
#endregion

#region Using..

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

#endregion

namespace pogra
{
    /// <summary>
    /// Klasa emitera cząsteczek. Przechowuje listę żywych cząsteczek,
    /// wywołuje ich metody draw i update oraz usuwa i dodaje nowe.
    /// </summary>
    public class Emitter
    {
        #region pola i właściwości

        protected Texture2D particleBase;
        protected Vector2 Position;
        protected Random random = new Random();
        protected int maxParticles;
        protected TimeSpan life = TimeSpan.FromSeconds(5);
        protected LinkedList<Particle> particleList = new LinkedList<Particle>();

        /// <summary>
        /// Aktualna pozycja emitera
        /// </summary>
        public Vector2 Pos
        {
            get { return Position; }
            set { Position = value; }
        }

        /// <summary>
        /// Aktualna długość życia emitera
        /// </summary>
        public TimeSpan Life
        {
            get { return life; }
        }

        #endregion

        #region inicjalizacja

        /// <summary>
        /// Tworzy nowy obiekt emitera
        /// </summary>
        public Emitter(Vector2 Position, Texture2D particleBase)
        {
            this.Position = Position;
            this.particleBase = particleBase;
            this.maxParticles = 350;

        }

        #endregion

        #region metody update i draw

        /// <summary>
        /// Metoda uaktualniania stanu emitera. Tworzy nowe cząsteczki 
        /// jeśli jest taka potrzeba, wywołuje ich metody update oraz 
        /// usuwa martwe.
        /// </summary>
        /// <param name="gameTime">czas, który upłynął od ostatniego update</param>
        /// <returns>zwraca true, jeżeli emitter wciąż jest żywy</returns>
        public bool Update(TimeSpan gameTime)
        {
            GenerateParticles();

            UpdateParticles(gameTime);

            miniUpdate(gameTime);

            return deathLogic();
        }

        /// <summary>
        /// Rysowanie cząsteczek należących do emittera
        /// </summary>
        /// <param name="exSpriteBatch">obiekt ExtendedSpriteBatch, za pomocą którego rysować cząsteczki</param>
        public void Draw(ExtendedSpriteBatch exSpriteBatch)
        {
            foreach (Particle part in particleList)
            {
                part.Draw(exSpriteBatch);
            }
        }

        #endregion

        #region metody protected

        /// <summary>
        /// Funkcja warunkująca smierć emitera.
        /// </summary>
        /// <returns>Zwraca true jeżeli emiter wciąż żyje.
        /// False w przeciwnym wypadku.
        /// </returns>
        protected virtual bool deathLogic()
        {
            if (life > TimeSpan.Zero || particleList.Count > 0)
                return true;
            else
                return false;
        }

        /// <summary>
        /// Funkcja generująca nowe cząsteczki.
        /// </summary>
        protected virtual void GenerateParticles()
        {
            // generacja nowych cząsteczek
            while (particleList.Count < maxParticles && life > TimeSpan.Zero)
            {
                Color color = Color.Gold;
                double lifeSeconds = random.NextDouble() * 0.1 + 0.1;
                double velocity = random.NextDouble() * 300 + 00;
                double rotation = random.NextDouble() * Math.PI*2;
                particleList.AddLast(new Particle(particleBase, Position, (float)velocity, (float)rotation, TimeSpan.FromSeconds(lifeSeconds)));
            }
        }

        /// <summary>
        /// Funkcja służąca do wykonywania czynnośći
        /// wewnątrz metody Update takich jak aktualizacja
        /// położenia emitera.
        /// </summary>
        protected virtual void miniUpdate(TimeSpan gameTime) { }

        #endregion

        #region metody prywatne

        /// <summary>
        /// Metoda wywołująca update cząsteczek i usuwająca martwe
        /// cząsteczki.
        /// </summary>
        private void UpdateParticles(TimeSpan gameTime)
        {
            LinkedListNode<Particle> node = particleList.First;
            while (node != null)
            {
                bool isAlive = node.Value.Update(gameTime);
                node = node.Next;

                if (!isAlive)
                {
                    if (node == null)
                        particleList.RemoveLast();
                    else
                        particleList.Remove(node.Previous);
                }
            }

            life -= gameTime;
        }

        #endregion
    }
}
